import os
import psutil
import ctypes
import sys
import time
import tkinter as tk
from tkinter import messagebox, scrolledtext, ttk
from datetime import datetime
import subprocess
import threading


# 全局变量存储检索到的路径和状态
exe_real_path = None
current_version = None
is_path_searched = False
is_searching = False
search_timeout = False
auto_detected = False  # 标记是否自动检测成功


# 进程管理相关函数
def is_admin():
    """检查是否以管理员权限运行"""
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False


def run_as_admin():
    """以管理员权限重新运行脚本"""
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)


def is_process_running(process_name):
    """检查指定名称的进程是否正在运行"""
    for proc in psutil.process_iter(['name']):
        if proc.info['name'].lower() == process_name.lower():
            return True
    return False


def terminate_process(process_name):
    """终止指定名称的所有进程"""
    terminated = False
    for proc in psutil.process_iter(['name', 'pid']):
        if proc.info['name'].lower() == process_name.lower():
            try:
                p = psutil.Process(proc.info['pid'])
                p.terminate()  # 尝试正常终止
                p.wait(timeout=5)  # 等待进程结束
                terminated = True
                log_message(f"已终止进程: {process_name} (PID: {proc.info['pid']})")
            except psutil.NoSuchProcess:
                log_message(f"进程已终止: {process_name} (PID: {proc.info['pid']})")
            except (psutil.AccessDenied, psutil.TimeoutExpired) as e:
                log_message(f"终止进程失败(可能需要管理员权限): {e}")
                if not is_admin():
                    log_message("正在尝试以管理员权限重新运行...")
                    run_as_admin()
                    return False
    return terminated


def kill_task(target_process):
    """Kill 已运行的程序"""
    if is_process_running(target_process):
        log_message(f"进程 {target_process} 正在运行，尝试终止...")
        if terminate_process(target_process):
            log_message(f"成功终止所有 {target_process} 进程")
        else:
            log_message(f"未能终止 {target_process} 进程")
    else:
        log_message(f"进程 {target_process} 未在运行")


# 自动检测功能
def auto_detect_running_wechat():
    """启动时自动检测正在运行的微信程序"""
    global exe_real_path, current_version, is_path_searched, auto_detected
    
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log_message(f"[{current_time}] 正在自动检测运行中的微信程序...")
    
    # 检测新版微信 (Weixin.exe)
    weixin_path = None
    wechat_path = None
    
    for proc in psutil.process_iter(['name', 'exe']):
        try:
            if proc.info['name'].lower() == 'weixin.exe':
                weixin_path = proc.info['exe']
                break
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    
    # 检测老版微信 (WeChat.exe)
    for proc in psutil.process_iter(['name', 'exe']):
        try:
            if proc.info['name'].lower() == 'wechat.exe':
                wechat_path = proc.info['exe']
                break
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    
    # 根据检测结果进行处理
    if weixin_path:
        # 检测到新版微信
        log_message(f"[{current_time}] 检测到新版微信正在运行")
        log_message(f"[{current_time}] 路径: {weixin_path}")
        
        auto_detected = True
        version_combobox.set("新版 (Weixin.exe)")
        version_combobox.config(state="disabled")  # 置灰版本选择框
        exe_real_path = weixin_path
        current_version = 'new'
        is_path_searched = True
        
        # 启用启动按钮
        start_button.config(state=tk.NORMAL)
        search_button.config(text="重新检索")
        
        log_message(f"[{current_time}] 自动检测成功！已选择新版微信并定位路径")
        log_message(f"[{current_time}] 版本选择已锁定，如需更改请点击重新检索")
        
    elif wechat_path:
        # 检测到老版微信
        log_message(f"[{current_time}] 检测到老版微信正在运行")
        log_message(f"[{current_time}] 路径: {wechat_path}")
        
        auto_detected = True
        version_combobox.set("老版 (WeChat.exe)")
        version_combobox.config(state="disabled")  # 置灰版本选择框
        exe_real_path = wechat_path
        current_version = 'old'
        is_path_searched = True
        
        # 启用启动按钮
        start_button.config(state=tk.NORMAL)
        search_button.config(text="重新检索")
        
        log_message(f"[{current_time}] 自动检测成功！已选择老版微信并定位路径")
        log_message(f"[{current_time}] 版本选择已锁定，如需更改请点击重新检索")
        
    else:
        # 没有检测到运行中的微信
        log_message(f"[{current_time}] 未检测到运行中的微信程序", is_error=True)
        log_message(f"[{current_time}] 提示：请先启动微信程序后再点击检索", is_error=True)
        
        # 版本选择框置灰，不允许用户选择
        version_combobox.config(state="disabled")
        
        # 显示提示对话框
        messagebox.showinfo(
            "自动检测结果",
            "未检测到运行中的微信程序\n\n请执行以下操作：\n"
            "1. 先启动微信客户端（新版或老版）\n"
            "2. 然后再点击检索按钮进行检测\n\n"
            "注意：版本选择已锁定，系统将根据运行的微信版本自动选择"
        )
        
        # 修改检索按钮文本
        search_button.config(text="检测运行的微信")
        
        log_message(f"[{current_time}] 版本选择已锁定，请先启动微信后再检测")
# 主程序功能
def on_start_clicked():
    """启动按钮点击事件处理"""
    global exe_real_path, is_path_searched

    # 获取当前时间用于日志
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    # 检查是否已检索路径
    if not is_path_searched or not exe_real_path:
        error_msg = "请先点击检索按钮获取微信路径"
        log_message(f"[{current_time}] 错误: {error_msg}", is_error=True)
        messagebox.showwarning("警告", error_msg)
        return

    # 记录开始操作日志
    log_message(f"[{current_time}] 开始启动程序...")

    quantity_str = quantity_combobox.get()

    if not quantity_str:
        error_msg = "请选择数量"
        log_message(f"[{current_time}] 错误: {error_msg}", is_error=True)
        messagebox.showwarning("警告", error_msg)
        return

    try:
        quantity_num = int(quantity_str)
        log_message(f"[{current_time}] 当前数量: {quantity_num}")
        # 调用处理函数
        process_quantity(quantity_num)
    except ValueError:
        error_msg = "请选择有效的数字"
        log_message(f"[{current_time}] 错误: {error_msg}", is_error=True)
        messagebox.showerror("错误", error_msg)


def process_quantity(quantity):
    """处理数量的函数"""
    global exe_real_path, current_version

    # 根据版本确定要kill的进程名
    process_name = 'Weixin.exe' if current_version == 'new' else 'WeChat.exe'

    # kill已运行的程序
    kill_task(process_name)

    for num in range(quantity):
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_message(f"[{current_time}] 正在启动第{num + 1}个程序")
        subprocess.Popen(exe_real_path, shell=True)
        log_message(f"[{current_time}] 第{num + 1}个程序启动成功!")

    success_msg = f"成功启动程序数量: {quantity}, 确认后3s后自动关闭当前窗口!"
    messagebox.showinfo("成功", success_msg)
    time.sleep(3)
    root.destroy()


def log_message(message, is_error=False):
    """在日志区域添加消息"""
    log_area.config(state=tk.NORMAL)
    if is_error:
        log_area.insert(tk.END, message + "\n", "error")
    else:
        log_area.insert(tk.END, message + "\n")
    log_area.config(state=tk.DISABLED)
    log_area.see(tk.END)  # 自动滚动到最后


def find_running_wechat_path(version='new'):
    """从正在运行的进程中查找微信路径"""
    exe_name = 'weixin.exe' if version == 'new' else 'wechat.exe'
    
    for proc in psutil.process_iter(['name', 'exe']):
        try:
            if proc.info['name'].lower() == exe_name:
                return proc.info['exe']
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    
    return None


def search_with_timeout(version_key, timeout_callback):
    """在单独线程中执行搜索操作"""
    global exe_real_path, is_searching, search_timeout

    try:
        if search_timeout:  # 检查是否已超时
            return

        result_path = find_running_wechat_path(version_key)
        
        if result_path and not search_timeout:
            exe_real_path = result_path
        elif not search_timeout:
            # 在主线程中显示错误
            root.after(0, lambda: search_error_callback("未找到正在运行的微信程序，请先启动微信"))
    except Exception as e:
        if not search_timeout:
            # 在主线程中显示错误
            root.after(0, lambda: search_error_callback(str(e)))
    finally:
        is_searching = False


def timeout_handler():
    """超时处理函数"""
    global search_timeout, is_searching

    if is_searching:
        search_timeout = True
        is_searching = False

        # 在主线程中显示超时消息
        root.after(0, show_timeout_message)


def show_timeout_message():
    """显示超时消息"""
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    selected_version = version_combobox.get()
    other_version = "老版 (WeChat.exe)" if selected_version == "新版 (Weixin.exe)" else "新版 (Weixin.exe)"

    error_msg = f"检索超时（超过6秒），未找到{selected_version}"
    log_message(f"[{current_time}] 错误: {error_msg}", is_error=True)

    # 重置按钮状态
    search_button.config(state=tk.NORMAL, text="检索")
    start_button.config(state=tk.DISABLED)

    # 显示超时提示消息
    messagebox.showerror(
        "检索超时",
        f"{error_msg}\n\n建议尝试以下操作：\n"
        f"1. 切换到 '{other_version}' 再次检索\n"
        f"2. 检查是否安装了对应版本的微信\n"
        f"3. 以管理员身份运行此程序"
    )


def search_error_callback(error_message):
    """搜索错误回调函数"""
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    error_msg = f"检索失败: {error_message}"
    log_message(f"[{current_time}] 错误: {error_msg}", is_error=True)

    selected_version = version_combobox.get()
    other_version = "老版 (WeChat.exe)" if selected_version == "新版 (Weixin.exe)" else "新版 (Weixin.exe)"

    # 重置按钮状态
    search_button.config(state=tk.NORMAL, text="检索")
    start_button.config(state=tk.DISABLED)

    messagebox.showerror(
        "检索失败",
        f"{error_msg}\n\n建议尝试以下操作：\n"
        f"1. 切换到 '{other_version}' 再次检索\n"
        f"2. 检查是否安装了对应版本的微信"
    )

def on_search_clicked():
    """检索按钮点击事件处理 - 带超时机制"""
    global exe_real_path, current_version, is_path_searched, is_searching, search_timeout

    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    # 检查是否正在搜索
    if is_searching:
        log_message(f"[{current_time}] 正在检索中，请稍候...", is_error=True)
        return

    # 如果是“检测运行的微信”按钮，重新执行自动检测
    if search_button.cget("text") == "检测运行的微信":
        log_message(f"[{current_time}] 重新检测运行中的微信程序...")
        auto_detect_running_wechat()
        return
        
    # 如果是重新检索，重新启用版本选择框
    if search_button.cget("text") == "重新检索":
        version_combobox.config(state="readonly")
        log_message(f"[{current_time}] 已重新启用版本选择，请选择版本后再次检索")

    # 获取选择的版本
    selected_version = version_combobox.get()
    if not selected_version:
        error_msg = "请先选择微信版本"
        log_message(f"[{current_time}] 错误: {error_msg}", is_error=True)
        messagebox.showwarning("警告", error_msg)
        return

    # 转换版本标识
    version_key = 'new' if selected_version == '新版 (Weixin.exe)' else 'old'
    current_version = version_key

    # 重置状态
    is_path_searched = False
    exe_real_path = None
    is_searching = True
    search_timeout = False

    # 更新按钮状态
    search_button.config(state=tk.DISABLED, text="检索中...")
    start_button.config(state=tk.DISABLED)

    log_message(f"[{current_time}] 开始检索{selected_version}路径...")
    log_message(f"[{current_time}] 检索超时设置为3秒，请稍候...")

    # 启动超时定时器
    timeout_timer = threading.Timer(3.0, timeout_handler)
    timeout_timer.start()

    # 在单独线程中执行搜索
    search_thread = threading.Thread(
        target=search_with_timeout,
        args=(version_key, timeout_handler)
    )
    search_thread.daemon = True
    search_thread.start()

    # 启动结果检查定时器
    check_search_result(timeout_timer)


def check_search_result(timeout_timer):
    """检查搜索结果的定时器"""
    global exe_real_path, is_path_searched, is_searching, search_timeout

    if search_timeout:
        # 已超时，不再检查
        timeout_timer.cancel()
        return

    if not is_searching and exe_real_path:
        # 搜索成功
        timeout_timer.cancel()
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        log_message(f"[{current_time}] 检索成功: {exe_real_path}")
        is_path_searched = True

        # 检索成功后锁定版本选择框
        version_combobox.config(state="disabled")

        # 恢复按钮状态
        search_button.config(state=tk.NORMAL, text="重新检索")
        start_button.config(state=tk.NORMAL)

        messagebox.showinfo("成功", f"检索成功!\n路径: {exe_real_path}")
        log_message(f"[{current_time}] 版本选择已锁定，如需更改请点击重新检索")

    elif is_searching:
        # 继续等待，100ms后再检查
        root.after(100, lambda: check_search_result(timeout_timer))


def on_version_changed(event=None):
    """版本选择改变时的回调函数"""
    global is_path_searched, exe_real_path, is_searching, search_timeout, auto_detected

    # 如果是自动检测的结果，不要重置状态
    if auto_detected:
        auto_detected = False
        return

    # 重置所有搜索相关状态
    is_path_searched = False
    exe_real_path = None
    is_searching = False
    search_timeout = False

    # 重置按钮状态
    search_button.config(state=tk.NORMAL, text="检索")
    start_button.config(state=tk.DISABLED)

    selected_version = version_combobox.get()
    if selected_version:
        log_message(f"已选择版本: {selected_version}，请点击检索按钮获取路径")


# 创建主窗口
def create_about_menu(window):
    """创建关于菜单"""
    menubar = tk.Menu(window)
    window.config(menu=menubar)

    help_menu = tk.Menu(menubar, tearoff=0)
    menubar.add_cascade(label="帮助", menu=help_menu)
    help_menu.add_command(label="关于", command=show_about_info)


def show_about_info():
    """显示关于信息窗口"""
    icon = os.path.join(os.path.dirname(__file__), 'images', 'favicon.ico')
    about_window = tk.Toplevel()
    about_window.title("关于")
    about_window.resizable(False, False)
    about_window.iconbitmap(icon)

    # 设置窗口居中
    window_width = 400
    window_height = 350
    screen_width = about_window.winfo_screenwidth()
    screen_height = about_window.winfo_screenheight()
    center_x = int(screen_width / 2 - window_width / 2)
    center_y = int(screen_height / 2 - window_height / 2)
    about_window.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')

    # 作者信息
    info_frame = tk.Frame(about_window)
    info_frame.pack(pady=10)

    tk.Label(info_frame, text="系统多开程序", font=('微软雅黑', 12, 'bold')).pack()
    tk.Label(info_frame, text="版本: v2.0.0").pack(pady=(10, 0))
    tk.Label(info_frame, text="作者: gguochen").pack()
    tk.Label(info_frame, text="联系方式: rysoft@139.com").pack()

    # 分隔线
    ttk.Separator(about_window, orient='horizontal').pack(fill='x', padx=10, pady=10)

    # 二维码区域
    qr_container = tk.Frame(about_window)
    qr_container.pack(pady=10)

    # 微信二维码区域
    wechat_qr_frame = tk.Frame(qr_container)
    wechat_qr_frame.pack(side=tk.LEFT, padx=(0, 20))

    tk.Label(wechat_qr_frame, text="微信联系", font=('微软雅黑', 10, 'bold')).pack()
    weRq = os.path.join(os.path.dirname(__file__), 'images', 'we_rq.png')
    try:
        # 加载微信二维码图片
        wechat_qr_image = tk.PhotoImage(file=weRq)
        wechat_qr_label = tk.Label(wechat_qr_frame, image=wechat_qr_image)
        wechat_qr_label.image = wechat_qr_image  # 保持引用
        wechat_qr_label.pack()
    except:
        tk.Label(wechat_qr_frame, text="[微信二维码图片]").pack()

    # 小程序二维码区域
    miniapp_qr_frame = tk.Frame(qr_container)
    miniapp_qr_frame.pack(side=tk.RIGHT, padx=(20, 0))

    tk.Label(miniapp_qr_frame, text="小程序体验", font=('微软雅黑', 10, 'bold')).pack()
    miniRq = os.path.join(os.path.dirname(__file__), 'images', 'mini_rq.png')
    try:
        # 加载小程序二维码图片
        mini_qr_image = tk.PhotoImage(file=miniRq)
        mini_qr_label = tk.Label(miniapp_qr_frame, image=mini_qr_image)
        mini_qr_label.image = mini_qr_image  # 保持引用
        mini_qr_label.pack()
    except:
        tk.Label(miniapp_qr_frame, text="[小程序二维码图片]").pack()

    # 关闭按钮
    close_button = tk.Button(
        about_window,
        text="关闭",
        command=about_window.destroy,
        width=10
    )
    close_button.pack(pady=10)


# 主窗口初始化
width = 500
height = 400
root = tk.Tk()
root.title("系统多开程序")
icon = os.path.join(os.path.dirname(__file__), 'images', 'favicon.ico')
root.iconbitmap(icon)
screen_width, screen_height = root.maxsize()

# 计算窗口居中位置
center_x = int(screen_width / 2 - width / 2)
center_y = int(screen_height / 2 - height / 2)
root.pack_propagate(False)
root.geometry(f'{width}x{height}+{center_x}+{center_y}')
root.update()

# 创建主框架
main_frame = tk.Frame(root)
main_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

# 输入区域
input_frame = tk.Frame(main_frame)
input_frame.pack(fill=tk.X)

# 版本选择行
version_frame = tk.Frame(input_frame)
version_frame.pack(fill=tk.X, pady=(0, 5))

tk.Label(version_frame, text="微信版本:").pack(side=tk.LEFT, padx=(0, 10))

version_combobox = ttk.Combobox(
    version_frame,
    values=["新版 (Weixin.exe)", "老版 (WeChat.exe)"],
    state="disabled",  # 初始状态为置灰
    width=20
)
version_combobox.pack(side=tk.LEFT, padx=(0, 10))
version_combobox.bind('<<ComboboxSelected>>', on_version_changed)

search_button = tk.Button(
    version_frame,
    text="检测运行的微信",  # 初始按钮文本
    command=on_search_clicked,
    width=12  # 略微增加宽度以适应文本
)
search_button.pack(side=tk.LEFT, padx=(0, 10))

# 数量选择行
quantity_frame = tk.Frame(input_frame)
quantity_frame.pack(fill=tk.X, pady=(5, 0))

tk.Label(quantity_frame, text="启动数量:").pack(side=tk.LEFT, padx=(0, 10))

quantity_combobox = ttk.Combobox(
    quantity_frame,
    values=["1", "2", "3", "4", "5"],
    state="readonly",
    width=10
)
quantity_combobox.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 10))
quantity_combobox.current(0)  # 默认选择1

start_button = tk.Button(
    quantity_frame,
    text="启动",
    command=on_start_clicked,
    width=10,
    state=tk.DISABLED  # 初始状态为禁用
)
start_button.pack(side=tk.RIGHT)

# 日志区域
log_frame = tk.Frame(main_frame)
log_frame.pack(fill=tk.BOTH, expand=True, pady=(10, 0))

tk.Label(log_frame, text="操作日志:").pack(anchor=tk.W)

log_area = scrolledtext.ScrolledText(
    log_frame,
    state=tk.DISABLED,
    wrap=tk.WORD,
    height=10
)
log_area.pack(fill=tk.BOTH, expand=True)

# 配置日志区域标签样式
log_area.tag_config("error", foreground="red")

# 添加初始日志
log_message("系统已启动")
log_message("正在进行自动检测...")

# 加载菜单栏
create_about_menu(root)

# 启动后自动检测
root.after(100, auto_detect_running_wechat)
# 运行主循环
root.mainloop()
